home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Magazin/MacEasy 11
/
Mac Magazin and MacEasy Magazine CD - Issue 11.iso
/
Sharewarebibliothek
/
Entwickler
/
CDEF-DeBugger 2.0 ƒ
/
CDEF Routines.c
< prev
next >
Wrap
Text File
|
1995-05-31
|
58KB
|
1,651 lines
// I included some of my own drawing definitions. Might want to check them out to understand them.
// I know that my intent was to make this as simple as possible, but for me this is simple. Nothing
// to complicated. Just some standard color definitions. Look at "MyColors.c" to see the functions.
// include files
#include <SetUpA4.h>
// Macros & defines
#define MY_THUMB_LENGTH 32 // simply put, this is the length of our thumb indicator.
// Prototypes
static pascal long MyControl( short variation, ControlHandle theControl, short message, long param );
void SetUpMyControl( CntlParam theParam );
void DrawMyControl( ControlHandle theControl, short part );
short TestMyControlParts( ControlHandle theControl, Point clickPnt );
void InitMyControl( ControlHandle theControl );
void DisposeMyControl( ControlHandle theControl );
void FillCntlParameters( ControlHandle theControl, CntlParmPtr *param );
void CalcMyThumbPosition( ControlHandle theControl, Rect *realThumbRect );
void DrawMyArrow( short var, Rect theRect );
void DragMyThumb( ControlHandle theControl, Point mousePnt );
void DragMyControl( ControlHandle theControl, Point mousePnt );
void DrawMyThumb( ControlHandle theControl, Boolean var );
void CalcMyThumbRgn( ControlHandle theControl, RgnHandle *param );
void PositionMyCntl( ControlHandle theControl, Point mousePnt );
void ConvertPtToVal( ControlHandle theControl, Point newPoint, short *value );
void DrawValueInThumb( ControlHandle theControl, long value );
// globals
extern Main myMain; // declared in Window-Main.c
/******************************************************************************
Your code resource function starts here.
variation - If you have varitions of this control and they were implemented
in you code, then if the user specifies one you will recieve it here.
Example: Code Resource ID * 16 + varition
theControl - a handle leading to the control record.
msg - this will be a message from the application to tell you what it
wants. It could be drawCntl, testCntl, etc.
param - this is a 4-byte value that is dependent on the msg.
Examples of some are below in the msg's.
*******************************************************************************/
static pascal long MyControl( short variation, ControlHandle theControl, short msg, long param )
{
Point mousePnt;
Boolean test;
SetUpA4();
HLock( (Handle)theControl );
if( (**theControl).contrlData ) {
HLock( (**theControl).contrlData );
}
// Use 'msg' to determine what the application is wanting our control to do.
switch( msg )
{
//------------------------------------------------------------------------------
//
// drawCntl ( message = 0 ) IM:Macintosh ToolBox Essentials : Page 5-111
//
// Draw the entire control or draw the part specified by LoWord( param ).
// Be sure to check the control's hilite value. If your control has an
// indicator or thumb and param = 129 you must erase the thumb from it's
// current position and redraw it according to the control's new value.
// Do not draw anything if the control is invisible.
//
// Return - A zero. (always)
//------------------------------------------------------------------------------
case drawCntl:
if( (**theControl).contrlVis == 255 ) {
DrawMyControl( theControl, LoWord( param ) );
}
return( 0L );
break;
//------------------------------------------------------------------------------
//
// testCntl ( message = 1 ) IM:Macintosh ToolBox Essentials : Page 5-112
//
// Check to see if the mouse point is in the control's rect or not.
// horizontal = LoWord( param )
// vertical = HiWord( param )
// This would be the area you create your parts if you have multiple things on
// your control. Like a thumb, arrows, pageUp, etc..
//
// Return - The part code of the part that contains the mouse point.
// Return zero if the mouse point is outside the part or
// the control is inactive.
//------------------------------------------------------------------------------
case testCntl:
// first extract the mouse position
mousePnt.h = LoWord( param );
mousePnt.v = HiWord( param );
// now determine if the mouse click was within our cntl rect.
if( PtInRect( mousePnt, &(**theControl).contrlRect )) {
// the click was inside our control so now define what part it was in.
return( TestMyControlParts( theControl, mousePnt ));
} else {
// the click wasn't within our control. Don't do anything.
return( 0L );
}
break;
//------------------------------------------------------------------------------
//
// calcCRgns ( message = 2 ) IM:Macintosh ToolBox Essentials : Page 5-112
//
// For non System 7.x systems. The low 3 bytes of param is a region handle.
// ( 4 bytes for 32-bit systems ). Mask the high byte and update the region
// to enclose the entire control. If the high bit is set then it's asking for
// the thumb or indicator. If not just use the entire control.
//
// Return - A zero. (always) Be sure to express the region in local coordinates.
//------------------------------------------------------------------------------
case calcCRgns:
if(( param & 0x80000000 ) == 0 ) {
// calculate the entire control.
RectRgn( (RgnHandle)(param & 0x00FFFFFF), &(**theControl).contrlRect );
} else {
// calculate only the indicator.
Rect realThumbRect;
// obtain the current thumb position
CalcMyThumbPosition( theControl, &realThumbRect );
RectRgn( (RgnHandle)(param & 0x00FFFFFF), &realThumbRect );
}
return( 0L );
break;
//------------------------------------------------------------------------------
//
// initCntl ( message = 3 ) IM:Macintosh ToolBox Essentials : Page 5-113
//
// Do any special inititailization, calculations or allocations here. For a
// standard scroll bar you would normally allocate the space for a region to
// the control's rect and region handles for the parts and store them in the
// 'contrlData' field in the control's record.
//
// Return - A zero. (always)
//------------------------------------------------------------------------------
case initCntl:
InitMyControl( theControl );
return( 0L );
break;
//------------------------------------------------------------------------------
//
// dispCntl ( message = 4 ) IM:Macintosh ToolBox Essentials : Page 5-113
//
// Do any special disposal of your control here.
//
// Return - A zero. (always)
//------------------------------------------------------------------------------
case dispCntl:
DisposeMyControl( theControl );
return( 0L );
break;
//------------------------------------------------------------------------------
//
// posCntl ( message = 5 ) IM:Macintosh ToolBox Essentials : Page 5-113
//
// Redraw the thumb and update the control's value.
// You use this wether you use default dragging or not.
// horizontal = LoWord( param ) = horizontal offset in pixels to move your indicator
// vertical = HiWord( param ) = vertical offset in pixels to move your indicator
//
// Return - A zero. (always)
//------------------------------------------------------------------------------
case posCntl:
// if you would like to test custom dragging comment out this function and
// un-comment the functions in 'dragCntl'. Leave return( 0L ) the same.
mousePnt.h = LoWord( param );
mousePnt.v = HiWord( param );
PositionMyCntl( theControl, mousePnt );
return( 0L );
break;
//------------------------------------------------------------------------------
//
// thumbCntl ( message = 6 ) IM:Macintosh ToolBox Essentials : Page 5-114
//
// When you recieve this message param points to a struct which you should
// fill with thumb motion constraints.
//
// struct {
// Rect limitRect; // on entry, top-left is the mouse point (local coord)
// // on exit this should be the same as the track rects
// // coordinates. ( take in account the thumb width )
// Rect slopRect; // if the user drags outiside this rect
// // the control will stop dragging.
// short axis; // The axis constraints the user may drag the control.
// // constants than can be used are:
// // noConstraint = 0; ( no constraint )
// // hAxisOnly = 1; ( drag horizontal only )
// // vAxisOnly = 2; ( drag vertical only )
//
// * these values are ignored if you use any custom dragging
//
// Return - Just fill in the struct.
//------------------------------------------------------------------------------
case thumbCntl:
FillCntlParameters( theControl, (CntlParmPtr*)¶m );
break;
//------------------------------------------------------------------------------
//
// dragCntl ( message = 7 ) IM:Macintosh ToolBox Essentials : Page 5-114
//
// If param = 0 then drag the entire control. If param = non-zero then
// just drag the indicator or thumb. For default dragging just return
// a 0 (zero). For custom dragging, follow the mouse around untill released
// then handle the details and return a non-zero.
// NOTE: If you do return a zero then you can ignore postCntl and thumbCntl.
//
// Return - For default dragging, return a zero. If your return something else
// then the control manager does not drag your control. But instead
// relies on your custom drag procedure.
//------------------------------------------------------------------------------
case dragCntl:
// if you would like to test these functions (custom dragging) remove
// the comments and comment out the functions in 'posCntl'
//GetMouse( &mousePnt );
//DragMyThumb( theControl, param, mousePnt );
//return( 1 );
return( 0L ); // comment out for custom dragging.
break;
//------------------------------------------------------------------------------
//
// autoTrack ( message = 8 ) IM:Macintosh ToolBox Essentials : Page 5-115
//
// This message will be sent if you specify -1 in the final parameter of
// TrackControl() and the contrlAction of the control is also -1. If so,
// LoWord( param ) will contain a part code and a handle to a routine
// to take care of it. Basically an action procedure as set by the user.
//------------------------------------------------------------------------------
case autoTrack:
break;
// The folowing messages are used only if the user is running System 7.x
// and when 32-bit addressing is enabled.
//------------------------------------------------------------------------------
//
// calcCntlRgn ( message = 10 ) IM:Macintosh ToolBox Essentials : Page 5-111
//
// This is essentially the same as calcCRgns except you do not have to
// mask out the high byte of the region handle. Used only when 32-bit
// addressing is on and running system 7.x. If running 24-bit addressing
// calcCRgns will still be used.
//
// Return - A zero (always) Be sure to express the region in local coordinates.
//------------------------------------------------------------------------------
case calcCntlRgn:
RectRgn( (RgnHandle)param, &(**theControl).contrlRect );
return( 0L );
break;
//------------------------------------------------------------------------------
//
// calcThumbRgn ( message = 11 ) IM:Macintosh ToolBox Essentials : Page 5-111
//
// This is asking you to calculate your indicator or thumb's region. Used
// only when 32-bit adressing is on and running system 7.x. If running
// 24-bit addressing calcCRgns will still be used.
//
// Return - A zero (always) Be sure to express the region in local coordinates.
//------------------------------------------------------------------------------
case calcThumbRgn:
CalcMyThumbRgn( theControl, (RgnHandle*)¶m );
return( 0L );
break;
}
HUnlock( (Handle)theControl );
if( (**theControl).contrlData ) {
HUnlock( (**theControl).contrlData );
}
RestoreA4();
}
/******************************************************************************
This procedure will steup you control when you are ready to allocate it.
It needs to be placed with the code up top
*******************************************************************************/
void SetUpMyControl( CntlParam theParam )
{
ControlDefUPP theControlDefUPP;
// store the CDEF UPP in the refCon of the control, the CDEF stub gets
// the address in the refCon and calls that UPP for CDEF messages
myMain.hControl = NewControl( theParam.theWindow,
&theParam.cntlRect,
theParam.title,
theParam.visible,
theParam.initialValue,
theParam.min,
theParam.max,
theParam.cntlType,
(long)NewControlDefProc( MyControl ) );
}
/******************************************************************************
Draw the control. Check to see if it's active and if so, what part to draw.
Also you need to check to see if the control is horizontal or vertical and
can we draw in color.
*******************************************************************************/
void DrawMyControl( ControlHandle theControl, short part )
{
Rect cntlRect, thumbRect, arrowLT, arrowRB, trackRect;
short cntlHilite, vCenter, hCenter;
RgnHandle arrow;
RGBColor theColor;
Point mousePnt;
MyCntlDataHan myData;
// retrieve the part information from the control's data field.
myData = (MyCntlDataHan)(**theControl).contrlData;
// Did we retrieve the data?
if( myData != nil ) {
// It worked, Alrighty then...
// set up some variables
cntlRect = (**theControl).contrlRect;
cntlHilite = (**theControl).contrlHilite;
thumbRect = (**myData).thumbRect;
arrowLT = (**myData).arrowLT;
arrowRB = (**myData).arrowRB;
trackRect = (**myData).trackRect;
// determine the centers for drawing. I haven't checked to see if I'm
// drawing a vertical or horizontal control. You will need to do this.
vCenter = ( cntlRect.bottom - cntlRect.top ) / 2;
hCenter = ( cntlRect.right - cntlRect.left ) / 2;
// Determine what the hilite state of the control is
if( cntlHilite == 255 )
{
// the control is inactive. Draw accordingly
SetForeColor( GREY_C );
FrameRect( &cntlRect );
FrameRect( &arrowLT );
FrameRect( &arrowRB );
CalcMyThumbPosition( theControl, &thumbRect );
FrameRect( &thumbRect );
ColorNormal();
} else {
// ok, so the control is active. now what part should we draw
switch( part )
{
//draw the entire control
case 0:
// ok first thing's first, let's erase the control. I'm checking to see
// what the control's owner's (window) content color is. Just to be nice.
GetWinBackColor( (**theControl).contrlOwner, &theColor );
RGBBackColor( &theColor );
EraseRect( &cntlRect );
//------------------------------------------------
// Draw left arrow
//
SetForeColor( GREY_B );
PaintRect( &arrowLT );
//--- add hilites and shadows
HiliteAndShadow( WHITE_COLOR, GREY_E, 0, arrowLT );
FrameRect( &arrowLT );
//--- add the black arrows. check to see if we are horz or vert
if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
// we are horizontal
DrawMyArrow( 0, arrowLT );
} else {
// we are vertical
DrawMyArrow( 1, arrowLT );
}
//------------------------------------------------
// Draw right arrow
//
SetForeColor( GREY_B );
PaintRect( &arrowRB );
//--- add hilites and shadows
HiliteAndShadow( WHITE_COLOR, GREY_E, 0, arrowRB );
FrameRect( &arrowRB );
//--- add the black arrows. check to see if we are horz or vert
if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
// we are horizontal
DrawMyArrow( 2, arrowRB );
} else {
// we are vertical
DrawMyArrow( 3, arrowRB );
}
//------------------------------------------------
// Draw the track part and the thumb. We put these
// together because we might have to erase an old thumb position.
//
DrawMyThumb( theControl, 0 );
break;
case 20: // inUpButton
//------------------------------------------------
// Let's erase the arrow's rect. Agin I'm getting the content color
// of the controls owner. (the window we're in)
//
GetWinBackColor( (**theControl).contrlOwner, &theColor );
RGBBackColor( &theColor );
EraseRect( &arrowLT );
GetMouse( &mousePnt );
if( PtInRect( mousePnt, &arrowLT ) && Button()) {
//------------------------------------------------
// Draw left arrow - inverted
//
SetForeColor( GREY_E );
PaintRect( &arrowLT );
//--- add hilites and shadows
HiliteAndShadow( GREY_H, GREY_B, 0, arrowLT );
FrameRect( &arrowLT );
//--- add the arrows. check to see if we are horz or vert
if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
// we are horizontal
DrawMyArrow( 0, arrowLT );
} else {
// we are vertical
DrawMyArrow( 1, arrowLT );
}
} else {
//------------------------------------------------
// Draw left arrow - normal
//
SetForeColor( GREY_B );
PaintRect( &arrowLT );
//--- add hilites and shadows
HiliteAndShadow( WHITE_COLOR, GREY_E, 0, arrowLT );
FrameRect( &arrowLT );
//--- add the arrows. check to see if we are horz or vert
if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
// we are horizontal
DrawMyArrow( 0, arrowLT );
} else {
// we are vertical
DrawMyArrow( 1, arrowLT );
}
}
ColorNormal();
break;
case 21: //inDownButton
//------------------------------------------------
// Let's erase the arrow's rect. Again I'm getting the content color
// of the controls owner. (the window we're in)
//
GetWinBackColor( (**theControl).contrlOwner, &theColor );
RGBBackColor( &theColor );
EraseRect( &arrowRB );
//________________________________________________
// We need to determine how we should draw the arrows. Is the user
// clicking on them or is it normal? If it is being clicked on then
// we should check where the mouse is and if the button is down. This
// will determine if we draw the control inverted or not.
//
GetMouse( &mousePnt );
if( PtInRect( mousePnt, &arrowRB ) && Button()) {
//------------------------------------------------
// Draw right arrow - inverted
//
SetForeColor( GREY_E );
PaintRect( &arrowRB );
//--- add hilites and shadows
HiliteAndShadow( GREY_H, GREY_B, 0, arrowRB );
FrameRect( &arrowRB );
//--- add the black arrows. check to see if we are horz or vert
if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
// we are horizontal
DrawMyArrow( 2, arrowRB );
} else {
// we are vertical
DrawMyArrow( 3, arrowRB );
}
} else {
//------------------------------------------------
// Draw right arrow - normal
//
SetForeColor( GREY_B );
PaintRect( &arrowRB );
//--- add hilites and shadows
HiliteAndShadow( WHITE_COLOR, GREY_E, 0, arrowRB );
FrameRect( &arrowRB );
//--- add the black arrows. check to see if we are horz or vert
if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
// we are horizontal
DrawMyArrow( 2, arrowRB );
} else {
// we are vertical
DrawMyArrow( 3, arrowRB );
}
}
ColorNormal();
break;
case 22: // inPageUp
case 23: // inPageDown
//------------------------------------------------
// All we need to do here is determine if we are to the left or right
// ( or top or bottom ) of the thumb's position. Then create a rect
// who's left or right ( top or bottom ) is that of the thumb's.
//
// get the current mouse position
GetMouse( &mousePnt );
// need to find if we are a vert or horz control. Only need to do this when
// we are inverting the control. We need to draw the entire control when
// asked to draw it normally. Why?!? Because when we invert it we create
// Hilites and shadows which need to be erased.
if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
// we are horizontal
// find out where our current thumb is located ( real corrdinates )
CalcMyThumbPosition( theControl, &thumbRect );
// where is the mouse? on the right or the left?
if( mousePnt.h <= thumbRect.left ) {
trackRect.right = thumbRect.left;
} else {
trackRect.left = thumbRect.right - 1;
}
} else {
// we are a vertical control
// find out where our current thumb is located ( real corrdinates )
CalcMyThumbPosition( theControl, &thumbRect );
// where is the mouse? on the top or the bottom?
if( mousePnt.v <= thumbRect.top ) {
trackRect.bottom = thumbRect.top + 1;
} else {
trackRect.top = thumbRect.bottom - 1;
}
}
// now figure out how to draw it. ( inverted or normal )
// and check to see if the are in the track portion or not.
if( PtInRect( mousePnt, &trackRect ) && Button()) {
//------------------------------------------------
// Draw the trackRect part ( not the thumb ) - inverted
//
InvertRect( &trackRect );
SetForeColor( GREY_C );
PaintRect( &trackRect );
//--- add hilites and shadows
HiliteAndShadow( GREY_G, WHITE_COLOR, 0, trackRect );
FrameRect( &trackRect );
} else {
//------------------------------------------------
// Draw the track part ( not the thumb ) - normal
//
SetForeColor( GREY_A );
PaintRect( &trackRect );
//--- add hilites and shadows
HiliteAndShadow( GREY_C, WHITE_COLOR, 0, trackRect );
FrameRect( &trackRect );
CalcMyThumbPosition( theControl, &thumbRect );
SetForeColor( GREY_B );
PaintRect( &thumbRect );
//--- add hilites and shadows
HiliteAndShadow( WHITE_COLOR, GREY_E, 0, thumbRect );
FrameRect( &thumbRect );
}
break;
case 129: // inThumb
// We don't have to do this here. Actually i don't believe it
// will even get called here. This has it's own routine I believe.
break;
}
}
} else {
// we had some problem retrieving our data
ReportError( "\pCouldn't retrieve data for drawing the control." );
}
}
/******************************************************************************
Test to see what part the user clicked in. We already checked to see if the
mouse click was actually inside the control. It was, so now see what part
they clicked in and return a number for it. Apple has a set of variables that
is uses for standard controls. So since our control is a variation of a normal
slider we'll use their variables. Check out FindControl() in IM or THINK Ref.
*******************************************************************************/
short TestMyControlParts( ControlHandle theControl, Point clickPnt )
{
Rect pageLeft, pageRight, realThumbRect, cntlRect;
MyCntlDataHan myData;
// For our own refrence let's define our parts..
//
// thumb = inThumb = 129
// arrowLT = inUpButton = 20
// arrowRB = inDownButton = 21
// pageLeft = inPageUp = 22
// pageRight = inPageDown = 23
// ok let's get our stored data from the control's contrlData field
myData = (MyCntlDataHan)(**theControl).contrlData; // force the data to form to our struct
// set up the control's rectangle for testing
cntlRect = (**theControl).contrlRect;
// we need to find out what the real thhumb on the control's rect is
CalcMyThumbPosition( theControl, &realThumbRect );
// double check to make sure that in fact we have data to play with
if( myData != nil ) {
// it worked. wow!
// now, all we do is test where exactly in the control the click was.
//is it in the thumb?
if( PtInRect( clickPnt, &realThumbRect ) ) {
return( inThumb );
} else {
// is it in one of the arrows?
if( PtInRect( clickPnt, &(**myData).arrowLT ) ) {
return( inUpButton );
} else {
if( PtInRect( clickPnt, &(**myData).arrowRB ) ) {
return( inDownButton );
} else {
// is it in the trackRect somewhere?
if( PtInRect( clickPnt, &(**myData).trackRect ) ) {
// we have to see if it's to the right of the thumb or left of it. Or if we are
// a vertical control the top and the bottom.
if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
// we have a horizontal control
pageLeft = pageRight = (**myData).trackRect;
pageLeft.right = realThumbRect.left;
pageRight.left = realThumbRect.right;
} else {
// we have a vertical control
pageLeft = pageRight = (**myData).trackRect;
pageLeft.bottom = realThumbRect.top;
pageRight.top = realThumbRect.bottom;
}
if( PtInRect( clickPnt, &pageLeft ) ) {
return( inPageUp );
} else {
if( PtInRect( clickPnt, &pageRight ) ) {
return( inPageDown );
}
}
} else {
// hey it wasn't in any of my rects. how'd that happ'n?
ReportError( "\pTesting points and couldn't find point within any of my parts." );
}
}
}
}
} else {
// retrieving the control's data failed.
ReportError( "\pCouldn't retrieve control data while testing the control." );
}
}
/******************************************************************************
When we recieve a 'initCntl' message in our control we use this procedure
to set up the 'contrlData' field in our control. This data is used to
store information about our control that we will use throughout it's life.
*******************************************************************************/
void InitMyControl( ControlHandle theControl )
{
Rect cntlRect, thumbRect, arrowLT, arrowRB, trackRect, slopRect;
short cntl_high = 0, cntl_wide = 0;
MyCntlDataHan myData;
// set our cntlRect to equal the control's rect.
cntlRect = (**theControl).contrlRect;
// we need to determine if we have a vertical or horizontal control
if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
// we have a horizontal control
// the first thing to do is determine the height of our control to make square arrows buttons
cntl_high = cntlRect.bottom - cntlRect.top;
// first we'll set the arrow buttons.
SetRect( &arrowLT, cntlRect.left, cntlRect.top, cntlRect.left + cntl_high, cntlRect.bottom );
SetRect( &arrowRB, cntlRect.right - cntl_high, cntlRect.top, cntlRect.right, cntlRect.bottom );
// Now we'll set the track's rectangle. Take the cntlRect - the arrow buttons.
trackRect = cntlRect;
trackRect.left = arrowLT.right - 1; // we want them to overlap.
trackRect.right = arrowRB.left + 1; // we want them to overlap.
// Now we'll set the thumb rect up. We don't have to actually set the rect
// to it's exact position, but just the size for now.
// Right = width
// Bottom = height (cntlRect's height - 2, so it's inset little.)
SetRect( &thumbRect, 0, 0, MY_THUMB_LENGTH, cntl_high - 2 );
} else {
// we have a vertical control
// the first thing to do is determine the width of our control to make square arrows buttons
cntl_wide = cntlRect.right - cntlRect.left;
// first we'll set the arrow buttons.
SetRect( &arrowLT, cntlRect.left, cntlRect.top, cntlRect.right, cntlRect.top + cntl_wide );
SetRect( &arrowRB, cntlRect.left, cntlRect.bottom - cntl_wide, cntlRect.right, cntlRect.bottom );
// Now we'll set the track's rectangle. Take the cntlRect - the arrow buttons.
trackRect = cntlRect;
trackRect.top = arrowLT.bottom - 1;
trackRect.bottom = arrowRB.top + 1;
// Now we'll set the thumb rect up. We don't have to actually set the rect
// to it's exact position, but just the size for now.
// Right = height (cntlRect's height - 2, so it's inset little.)
// Bottom = width
SetRect( &thumbRect, 0, 0, cntl_wide - 2, MY_THUMB_LENGTH );
}
// we need to set the size of the handle we are using
myData = (MyCntlDataHan)NewHandle( sizeof( MyCntlData ) );
if( myData != nil ) {
// now store our handle in the contrlData field in the control record
(**theControl).contrlData = (Handle)myData;
// now simply copy this information into our handle.
(**myData).cntlRect = cntlRect;
(**myData).thumbRect = thumbRect;
(**myData).arrowLT = arrowLT; // left or top arrow
(**myData).arrowRB = arrowRB; // right or bottom arrow
(**myData).trackRect = trackRect;
} else {
// We had any error. Respond what error had occured.
ReportError( "\pCouldn't allocate area for the data handle." );
}
}
/******************************************************************************
This procedure will get called when we recieve a 'dispCntl' in the
param of our control. All we need to do is distroy any data that we
initialized earlier in the 'initCntl' procedure.
*******************************************************************************/
void DisposeMyControl( ControlHandle theControl )
{
MyCntlDataHan myData;
if( theControl != nil ) {
// Get the handle to the control's data.
myData = (MyCntlDataHan)(**theControl).contrlData;
if( myData != nil ) {
// lock the structs data.
HLock( (Handle) myData );
// dispose of our data handle and set the contrlData field to nil.
DisposeHandle( (Handle) myData );
(**theControl).contrlData = nil;
} else {
// error occurred trying to retreive info from the control's data field.
ReportError( "\pCouldn't retrieve control data information." );
}
} else {
// For some reason we didn't get a true control handle passed to us
ReportError( "\pTried to extract data information, but was passed a bad control handle." );
}
}
/******************************************************************************
Out Control recieved a 'thumbCntl' message. We need to fill in the parameters
of the controls limit rect and slop rect and axis.
By the way, CntlParm is a struct defined on top. We use it here to set up
or force the data that lies within 'param' to match our requirements.
*******************************************************************************/
void FillCntlParameters( ControlHandle theControl, CntlParmPtr *param )
{
Rect limitRect, slopRect, cntlRect, realThumbRect;
short axis;
Point mousePnt;
MyCntlDataHan myData;
// You may be asking yourself, "What exactly are we doing here?"
// Well we are setting some parameters, that Apple has provided
// us control definition makers, to allow some helpful human
// interaction. ( At least I think so ).
//
// The limitRect gives us the mouse coordinates on entry. On exit
// this rect should contain the control track rectangle. The slopRect
// gives us an area in which the user can drag outside the control's
// rectangle in which the control will still respond. If the user moves
// outside this 'slop rectangle' then the control will return to it's
// previous state. The axis constrain the drag movement depending on the
// setting. noContraint = 0 ( no constraint ), hAxisOnly = 1 ( horizontal only ),
// vAxisOnly = 2 ( vertical only ).
// extract data from the contrlData field and form to our struct.
myData = (MyCntlDataHan)(**theControl).contrlData;
// let's get the true or real thumb rect ( the one that gets drawn )
CalcMyThumbPosition( theControl, &realThumbRect );
// set the cntlRect to match the control's rectangle
cntlRect = (**theControl).contrlRect;
// extract the mouse down points from param
mousePnt.h = (**param).limitRect.left;
mousePnt.v = (**param).limitRect.top;
if( myData != nil ) {
// now let's determine if we are using a horz or vert control
if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
// we have ourselves a horizontal control
// adjust the limitRect to take in account where the user clicked whithin the thumb
(**param).limitRect.left = (**myData).arrowLT.right + ( mousePnt.h - realThumbRect.left );
(**param).limitRect.right = (**myData).arrowRB.left - ( (realThumbRect.right-1) - mousePnt.h );
// now let's adjust the slopRect slightly, increase it by 20 pixels...
(**param).slopRect = (**myData).trackRect;
InsetRect( &(**param).slopRect, -20, -20 );
// then extend it's edges about 100 pixels. This normally gives the correct feel.
(**param).slopRect.left -= 100;
(**param).slopRect.right += 100;
// set up the axis for a horizontal control
(**param).axis = hAxisOnly;
} else {
// we have a vertical control.
// adjust the limitRect to take in account where the user clicked whithin the thumb
(**param).limitRect.top = (**myData).arrowLT.bottom + ( mousePnt.v - realThumbRect.top );
(**param).limitRect.bottom = (**myData).arrowRB.top - ( (realThumbRect.bottom-1) - mousePnt.v );
// now let's adjust the slopRect slightly, increase it by 20 pixels...
(**param).slopRect = (**myData).trackRect;
InsetRect( &(**param).slopRect, -20, -20 );
// then extend it's edges about 100 pixels. This normally gives the correct feel.
slopRect.top -= 100;
slopRect.bottom += 100;
// set up the axis for the control
(**param).axis = vAxisOnly;
}
} else {
// we had an error retreiving data form the control
ReportError( "\pWe couldn't extract data from the control while calculating the parameters." );
}
}
/******************************************************************************
This is a fairly straight forward procedure. All we have to do is find the position of
the thumb on the track and return a rect to match these values. Easy shmeazy. All
we are doing here is calculating the "Real Thumb Rect" for drawing.
*******************************************************************************/
void CalcMyThumbPosition( ControlHandle theControl, Rect *realThumbRect )
{
long min, max, value, dist;
short cntl_high, cntl_wide;
Rect cntlRect, trackRect;
MyCntlDataHan myData;
// Do some initial setting up
cntlRect = (**theControl).contrlRect;
min = (**theControl).contrlMin;
max = (**theControl).contrlMax;
value = (**theControl).contrlValue;
myData = (MyCntlDataHan)(**theControl).contrlData; // force the data to form to our struct
// double check to make sure that in fact we have data to play with
if( myData != nil ) {
// it worked! cool...
// make sure the value isn't greater or less than max & min
if( value > max ) {
value = max;
} else {
if( value < min ) {
value = min;
}
}
// retrieve the track rect from our data
trackRect = (**myData).trackRect;
// Do we have a horizontal or vertical control???
if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top )
{
// We have horizontal control
// We need to set the trackRect to take in account of the thumb width.
// We do this so we don't overwrite part of the arrow when we are drawing.
trackRect.left += ( MY_THUMB_LENGTH / 2 ) + 1;
trackRect.right -= ( MY_THUMB_LENGTH / 2 ) + 1;
// determine how wide our track rect is and then calculate the distance we move.
cntl_wide = trackRect.right - trackRect.left;
dist = trackRect.left + (((max + value) * cntl_wide) / (max - min)) - ( MY_THUMB_LENGTH / 2 );
// we know that the top and bottom of our thumb rect will be the same as the
// control's rect (basically). It's actually inset 1 pixel to fit inside the track.
(*realThumbRect).top = cntlRect.top + 1;
(*realThumbRect).bottom = cntlRect.bottom - 1;
// now set the left and right to the correct coordinates for drawing.
(*realThumbRect).left = (**myData).thumbRect.left + dist;
(*realThumbRect).right = (**myData).thumbRect.right + dist;
} else {
// We have a vertical control
// We need to set the trackRect to take in account of the thumb width.
// We do this so we don't overwrite part of the arrow when we are drawing.
trackRect.top += ( MY_THUMB_LENGTH / 2 ) + 1;
trackRect.bottom -= ( MY_THUMB_LENGTH / 2 ) + 1;
// determine how tall our track rect is and then calculate the distance we move.
cntl_high = trackRect.bottom - trackRect.top;
dist = trackRect.top + (((max + value) * cntl_high) / (max - min)) - ( MY_THUMB_LENGTH / 2 );
// we know that the left and right of our thumb rect will be the same as the
// control's rect (basically). It's actually inset 1 pixel to fit inside the track.
(*realThumbRect).left = cntlRect.left + 1;
(*realThumbRect).right = cntlRect.right - 1;
// now set the top and bottom to the correct coordinates for drawing.
(*realThumbRect).top = (**myData).thumbRect.top + dist;
(*realThumbRect).bottom = (**myData).thumbRect.bottom + dist;
}
} else {
// we had a problem getting our data. bummer!
ReportError( "\pTrying to calculate thumb postion and couldn't access data field." );
}
}
/******************************************************************************
This procedure will draw the black arrows located in my arrow buttons.
you pass it a variable that tells which way the arrow should point and a
rect in which the arrow will be drawn. Fairly straight forward.
0 = points left
1 = points up
2 = points right
3 = points down
*******************************************************************************/
void DrawMyArrow( short var, Rect theRect )
{
RgnHandle arrow;
short center;
arrow = NewRgn();
OpenRgn();
switch( var ) {
case 0: // points left
center = ( theRect.bottom - theRect.top ) / 2;
MoveTo( theRect.left + 5, theRect.top + center );
LineTo( theRect.right - 6, theRect.top + 2 );
LineTo( theRect.right - 6, theRect.bottom - 4 );
LineTo( theRect.left + 5, theRect.bottom - center );
break;
case 1: // points up
center = ( theRect.right - theRect.left ) / 2;
MoveTo( theRect.left + 1, theRect.bottom - 6 );
LineTo( theRect.left + center - 1, theRect.top + 5 );
LineTo( theRect.right - 3, theRect.bottom - 6 );
LineTo( theRect.left + 1, theRect.bottom - 6 );
break;
case 2: // points right
center = ( theRect.bottom - theRect.top ) / 2;
MoveTo( theRect.right - 5, theRect.top + center + 1 );
LineTo( theRect.left + 6, theRect.top + 3 );
LineTo( theRect.left + 6, theRect.bottom - 4 );
LineTo( theRect.right - 5, theRect.bottom - center - 1 );
break;
case 3: // points down
center = ( theRect.right - theRect.left ) / 2;
MoveTo( theRect.left + 2, theRect.top + 6 );
LineTo( theRect.left + center, theRect.bottom - 5 );
LineTo( theRect.right - 4, theRect.top + 6 );
LineTo( theRect.left + 2, theRect.top + 6 );
break;
}
CloseRgn( arrow );
FillRgn( arrow, &black );
DisposeRgn( arrow );
}
/******************************************************************************
Custom Dragging Procedure - not needed if you use default dragging.
( when TrackControl is passed a zero for
the tracking procedure )
Used to move the indicator or thumb.
This procedure will show the user the interaction when they click on the
thumb part of our control. All we are going to do is drag the thumb's
rect around using the drag grey rgn routine untill the user let's up on the
mouse. For kicks and grins we will also draw the control's value above the
indicator. We also will use the parameters that we set for slop rect and limit rect.
*******************************************************************************/
void DragMyThumb( ControlHandle theControl, Point mousePnt )
{
RgnHandle thumbRgn;
Rect slopRect, limitRect, realThumbRect, cntlRect;
long newPoint;
MyCntlDataHan myData;
short value, axis;
// set up some variables..
myData = (MyCntlDataHan)(**theControl).contrlData; // force the data to form to our struct
cntlRect = (**theControl).contrlRect;
// double check to make sure that in fact we have data to play with
if( myData != nil ) {
// it worked, hurray.
// let's get the true or real thumb rect ( the one that gets drawn )
CalcMyThumbPosition( theControl, &realThumbRect );
// this is where we are declaring the parameters for dragging.
slopRect = limitRect = (**myData).trackRect;
// now let's determine if we are using a horz or vert control
if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
// we have ourselves a horizontal control
// adjust the limitRect to take in account where the user clicked whithin the thumb
limitRect.left = (**myData).arrowLT.right + ( mousePnt.h - realThumbRect.left );
limitRect.right = (**myData).arrowRB.left - ( (realThumbRect.right-1) - mousePnt.h );
// now let's adjust the slopRect slightly, increase it by 20 pixels...
InsetRect( &slopRect, -20, -20 );
// then extend it's edges about 100 pixels. This normally gives the correct feel.
slopRect.left -= 100;
slopRect.right += 100;
// define our axis that we will use to constrain the indicators movement.
axis = hAxisOnly;
} else {
// we have a vertical control.
// adjust the limitRect to take in account where the user clicked whithin the thumb
limitRect.top = (**myData).arrowLT.bottom + ( mousePnt.v - realThumbRect.top );
limitRect.bottom = (**myData).arrowRB.top - ( (realThumbRect.bottom-1) - mousePnt.v );
// now let's adjust the slopRect slightly, increase it by 20 pixels...
InsetRect( &slopRect, -20, -20 );
// then extend it's edges about 100 pixels. This normally gives the correct feel.
slopRect.top -= 100;
slopRect.bottom += 100;
// define our axis that we will use to constrain the indicators movement.
axis = vAxisOnly;
}
// we've been asked to only move the indicator
// now do our dragging. first declare a new rgn to copy out thumb rect into.
// then this gets passed to the DragGrayRgn() procedure. It actually handles the dragging.
thumbRgn = NewRgn();
RectRgn( thumbRgn, &realThumbRect );
// This is the actual routine to drag the indicator. For a more detailed explanation
// look on page 4-96 in IM:Toolbox Essentails or use Think Refrence.
newPoint = DragGrayRgn( thumbRgn, mousePnt, &limitRect, &slopRect, axis, nil );
// now determine if the thumb did in fact move. if DragGrayRgn() returns a value of
// 0x80008000 it means that the user realeased the mouse outside the sloprect. HiWord
// of newPoint is the vertical dist moved where as the LoWord is horz dist moved.
if( newPoint != 0x80008000 ) {
// It was released inside our control. newPoint will contain the horizontal and vertical
// ditance moved.
mousePnt.h = LoWord( newPoint );
mousePnt.v = HiWord( newPoint );
ConvertPtToVal( theControl, mousePnt, &value );
SetCtlValue( theControl, value );
DrawMyThumb( theControl, 1 );
DrawValueInThumb( theControl, value );
} else {
// it was released outside the slopRect. Do nothing
ReportError( "\pYou released the mouse outside the slop Rect." );
}
DisposeRgn( thumbRgn );
} else {
// it didn't work
ReportError( "\pCouldn't retrieve control data while dragging the control's thumb." );
}
}
/******************************************************************************
Custom Dragging Procedure - not needed if you use default dragging.
( when TrackControl is passed a zero for
the tracking procedure )
Used to move the entire control.
This procedure is only used when the user is given the ability to move
the entire control. I really haven't thought of any reason to do this, but
if it's something that is implicated in your code then here it is.
limitRect - will most likely be the control's ownern's content region.
slopRect - will be whatever value you think should be used. for tutorial
purposes I'll use the window's content region inset -20
axis - I'll assume that you would want to give them complete freedom.
No constraint.
*******************************************************************************/
void DragMyControl( ControlHandle theControl, Point mousePnt )
{
Rect slopRect, limitRect, cntlRect;
short axis;
WindowPtr cntlWindow;
// set up some variables..
cntlRect = (**theControl).contrlRect;
cntlWindow = (**theControl).contrlOwner;
// this is where we are declaring the parameters for dragging.
slopRect = limitRect = (*cntlWindow).portRect;
// now let's determine if we are using a horz or vert control
if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
// we have ourselves a horizontal control
// adjust the limitRect to take in account where the user clicked whithin the control
limitRect.left = cntlRect.left + mousePnt.h;
limitRect.right = cntlRect.right - mousePnt.h;
// now let's adjust the slopRect slightly, increase it by 20 pixels...
InsetRect( &slopRect, -20, -20 );
// define our axis that we will use to constrain the indicators movement.
axis = noConstraint;
} else {
// we have a vertical control.
// adjust the limitRect to take in account where the user clicked whithin the control
limitRect.top = cntlRect.top + mousePnt.v;
limitRect.bottom = cntlRect.bottom - mousePnt.v;
// now let's adjust the slopRect slightly, increase it by 20 pixels...
InsetRect( &slopRect, -20, -20 );
// define our axis that we will use to constrain the indicators movement.
axis = noConstraint;
}
// This is the actual routine used to drag the entire control for a more detailed
// exlpaination look on page 5-99 IM:Toolbox Essentails or use Think Refrence.
DragControl( theControl, mousePnt, &limitRect, &slopRect, axis );
}
/******************************************************************************
All this procedure does is draw the thumb depending on the current control
value. Fairly straight forward procedure. It will get called after the
user drags the thumb and if the control recieves a draw entire control msg.
I added a simply variable to tell my drawing procedure if I'm drawing for
custom dragging or default dragging. Since I didn't do anything to wild
for my dragging I'm using this instead. If the value is 0 then it just
draws the thumb normally. If anything else it draws it with the value in
the middle.
*******************************************************************************/
void DrawMyThumb( ControlHandle theControl, Boolean var )
{
Rect realThumbRect, trackRect;
MyCntlDataHan myData;
// set up some variables..
myData = (MyCntlDataHan)(**theControl).contrlData; // force the data to form to our struct
// double check to make sure that in fact we have data to play with
if( myData != nil ) {
// it worked we have data to play with
// first draw the track ( to erase any old thumb positions )
trackRect = (**myData).trackRect;
SetForeColor( GREY_A );
PaintRect( &trackRect );
//--- add hilites and shadows
HiliteAndShadow( GREY_C, WHITE_COLOR, 0, trackRect );
FrameRect( &trackRect );
//--- since we now know how large our thumb is, where should we draw it?
//--- the position is stored in the control's value field.
CalcMyThumbPosition( theControl, &realThumbRect );
SetForeColor( GREY_B );
PaintRect( &realThumbRect );
//--- add hilites and shadows
HiliteAndShadow( WHITE_COLOR, GREY_E, 0, realThumbRect );
FrameRect( &realThumbRect );
if( var != 0 ) {
// draw the text in the middle
DrawValueInThumb( theControl, (**theControl).contrlValue );
}
} else {
// we couldn't obtain the data for some reason.
ReportError( "\pCouldn't access control data while attempting to draw the thumb." );
}
}
/******************************************************************************
All we do here is calculate our thumb rect, convert to a region and copy it
into param (which is asking for a region handle) This is done so that the
user can drag our thumb.
*******************************************************************************/
void CalcMyThumbRgn( ControlHandle theControl, RgnHandle *param )
{
Rect realThumbRect;
// first let's find the real thumb rect
CalcMyThumbPosition( theControl, &realThumbRect );
// now just convert it into a rgn (using the pointer to param )
RectRgn( *param, &realThumbRect );
}
/******************************************************************************
Our control was sent a 'posCntl' in the message parameter. param contains the
horizontal and vertical offset to move your indicator from it's current
position. ( vert = HiWord, horz = LoWord ).
We will calculate the new setting and then redraw the control and update
it's control value.
This one through me for a loop. I wasn't recieving a posCntl for the life of
me. I figured out that I wasn't setting the param correctly in FillCntlParameters().
I wasn't forcing the data within param to my struct 'CntlParms' correctly. I
was forgetting to typeCast the param when sending it to my function. It's
the little things like that that will drive you crazy.
*******************************************************************************/
void PositionMyCntl( ControlHandle theControl, Point mousePnt )
{
short value;
// All we have to do is calculate the new thumb value and then
// use CalcMyThumbPosition() to figure out the new location
// of the thumb. TrackControl() will handle the draggin if things
// are set up correctly in FillCntlParameters().
// First convert the point given to us into a new value
ConvertPtToVal( theControl, mousePnt, &value );
// set the control's value to this new value
SetCtlValue( theControl, value );
// Now just redraw the indicator or thumb.
DrawMyThumb( theControl, 0 );
}
/******************************************************************************
This procedure will take a point that is within the track Rectangle
and convert it to a value.
*******************************************************************************/
void ConvertPtToVal( ControlHandle theControl, Point newPoint, short *value )
{
Rect trackRect, cntlRect, realThumbRect;
short currThumbCenter, newThumbCenter, trackWidth;
long min, max, newValue;
MyCntlDataHan myData;
// extract the control data and form to our struct.
myData = (MyCntlDataHan)(**theControl).contrlData;
// double check to make sure that in fact we have data to play with
if( myData != nil ) {
// set up some initial variables
trackRect = (**myData).trackRect;
cntlRect = (**theControl).contrlRect;
min = (**theControl).contrlMin;
max = (**theControl).contrlMax;
if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
// it's a horizontal control
// take in account the thumb length for the edges of the track. I added one
// because it had a tendancy to round down and not set my complete value.
trackRect.right -= ( MY_THUMB_LENGTH / 2 ) + 1;
trackRect.left += ( MY_THUMB_LENGTH / 2 ) + 1;
// we need to obtain the center of the current thumb position
CalcMyThumbPosition( theControl, &realThumbRect );
currThumbCenter = realThumbRect.left + (( realThumbRect.right - realThumbRect.left ) / 2 );
// determine the thumbs new center with the given offset.
newThumbCenter = currThumbCenter + newPoint.h;
// make sure the point isn't outside the track now that we made adjustments.
if( newThumbCenter < trackRect.left ) {
newThumbCenter = trackRect.left;
} else {
if( newThumbCenter > trackRect.right ) {
newThumbCenter = trackRect.right;
}
}
// find the width of our track rect
trackWidth = trackRect.right - trackRect.left;
// calculate our new value.
newValue = min + ( ( max - min ) * ( newThumbCenter - trackRect.left ) ) / trackWidth;
} else {
// it's a vertical control
// take in account the thumb length for the edges of the track.
trackRect.bottom -= ( MY_THUMB_LENGTH / 2 ) + 1;
trackRect.top += ( MY_THUMB_LENGTH / 2 ) + 1;
// we need to obtain the center of the current thumb position
CalcMyThumbPosition( theControl, &realThumbRect );
currThumbCenter = realThumbRect.top + (( realThumbRect.bottom - realThumbRect.top ) / 2 );
// determine the thumbs new center with the given offset.
newThumbCenter = currThumbCenter + newPoint.v;
// make sure the point isn't outside the track now that we made adjustments.
if( newThumbCenter < trackRect.top ) {
newPoint.v = trackRect.top;
} else {
if( newThumbCenter > trackRect.bottom ) {
newPoint.v = trackRect.bottom;
}
}
// find the height of our track rect
trackWidth = trackRect.bottom - trackRect.top;
// calculate our new value.
newValue = min + ( ( max - min ) * ( newThumbCenter - trackRect.top ) ) / trackWidth;
}
*value = newValue;
} else {
// We had problems extracting the data from the control's data field
ReportError( "\pCouldn't access the control's data while converting a point to a value." );
}
}
/******************************************************************************
Custom Dragging Procedure - not needed if you use default dragging.
( when TrackControl is passed a zero for
the tracking procedure )
Used to draw the controls value within the thumb.
This is just to show an example of how you could use custom dragging. This
is anything to fancy. Will just take the contol's value. Make sure it will
fit within our thumb and draw it in its center. For the sake of simplicity
we will not do this for a vertical control.
In reality you could use this for default draggin also, but I justed wanted
to show you something. I'm using a standard drag procedure for my custom
dragging so you really don't notice any big difference. This at least shows
some difference.
*******************************************************************************/
void DrawValueInThumb( ControlHandle theControl, long value )
{
Rect realThumbRect, cntlRect;
Str15 numString, errString = "\p???"; // will never be greater than 4 digits with our values.
short center, strWidth; // used to draw our text.
GrafPtr thePort; // used to get font info
short txFont, txSize, txFace, txMode; // to store current font info.
RGBColor theColor;
// first it helps to set the cntlRect
cntlRect = (**theControl).contrlRect;
if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
// we have a horizontal control
// we do this to find out current font settings.
GetPort( &thePort );
// Set up some variables and also find & change the current font information
NumToString( value, numString );
cntlRect = (**theControl).contrlRect;
txFont = (*thePort).txFont;
txSize = (*thePort).txSize;
txFace = (*thePort).txFace;
txMode = (*thePort).txMode;
GetBackColor( &theColor );
TextFont( 9 );
TextSize( 9 );
TextFace( 0 );
TextMode( 0 ); // for this to work and erase the background we need to
// be sure to set the background color to the thumb color.
SetBackColor( GREY_B ); // this is the thumbs color
// find the real thumb position
CalcMyThumbPosition( theControl, &realThumbRect );
// let's double check to make sure our value is bigger than four digits
if( numString[0] > 0x04 ) {
// we can't have that happen
BlockMove( &errString[0], &numString[0], 4 );
}
center = realThumbRect.left + (( realThumbRect.right - realThumbRect.left ) / 2 );
strWidth = StringWidth( numString );
MoveTo( center - ( strWidth / 2 ), realThumbRect.bottom - 4 );
DrawString( numString );
// redraw hilites and shadows on the thumb because we overWrite them slightly
HiliteAndShadow( WHITE_COLOR, GREY_E, 0, realThumbRect );
FrameRect( & realThumbRect );
// be nice and return everything back to the way they were.
TextFont( txFont );
TextSize( txSize );
TextFace( txFace );
TextMode( txMode );
RGBBackColor( &theColor );
} else {
// we have a vertical control so let's not bother
}
}